## Happy Hare supporting macros

#[save_variables]
#filename: /home/pi/printer_data/config/mmu/mmu_vars.cfg

########################################################################
# Tool change macros
# This is automatically created on installation but you can increase
# or reduce this list to match your number of tools in operation
#######################################################################
#[gcode_macro T0]
#gcode: MMU_CHANGE_TOOL TOOL=0
#[gcode_macro T1]
#gcode: MMU_CHANGE_TOOL TOOL=1
#[gcode_macro T2]
#gcode: MMU_CHANGE_TOOL TOOL=2
#[gcode_macro T3]
#gcode: MMU_CHANGE_TOOL TOOL=3
#[gcode_macro T4]
#gcode: MMU_CHANGE_TOOL TOOL=4
#[gcode_macro T5]
#gcode: MMU_CHANGE_TOOL TOOL=5
#[gcode_macro T6]
#gcode: MMU_CHANGE_TOOL TOOL=6
#[gcode_macro T7]
#gcode: MMU_CHANGE_TOOL TOOL=7
#[gcode_macro T8]
#gcode: MMU_CHANGE_TOOL TOOL=8
#[gcode_macro T9]
#gcode: MMU_CHANGE_TOOL TOOL=9
#[gcode_macro T10]
#gcode: MMU_CHANGE_TOOL TOOL=10
#[gcode_macro T11]
#gcode: MMU_CHANGE_TOOL TOOL=11



########################################################################
# Simplified subset of commands just for visability in Mainsail/Fluidd UI
# until custom panel is complete!
# The __ is a trick because it is not displayed by the UI but the fact
# the macros are defined here means they are still seen by Mainsail/Fluidd
########################################################################
[gcode_macro MMU__EJECT]
gcode: MMU_EJECT

[gcode_macro MMU__HOME]
gcode:
    {% set TOOL = params.TOOL|default(0)|int %}
    {% set FORCE_UNLOAD = params.FORCE_UNLOAD|default(0)|int %}
    MMU_HOME TOOL={TOOL} FORCE_UNLOAD={FORCE_UNLOAD}

[gcode_macro MMU__STATUS]
gcode: MMU_STATUS

[gcode_macro MMU__MOTORS_OFF]
gcode: MMU_MOTORS_OFF

[gcode_macro MMU__SERVO]
gcode:
    {% set POS = params.POS|default("up")|string %}
    MMU_SERVO POS={POS}

[gcode_macro MMU__SELECT_TOOL]
gcode:
    {% set TOOL = params.TOOL|default(0)|int %}
    MMU_SELECT TOOL={TOOL}

[gcode_macro MMU__SELECT_BYPASS]
gcode: MMU_SELECT_BYPASS

[gcode_macro MMU__LOAD_BYPASS]
gcode: MMU_LOAD

[gcode_macro MMU__RECOVER]
gcode: MMU_RECOVER

[gcode_macro MMU__PRELOAD]
gcode:
    {% set GATE = params.GATE|default(0)|int %}
    MMU_PRELOAD GATE={GATE}

[gcode_macro MMU__CHECK_GATE]
gcode:
    {% set GATE = params.GATE|default(-1)|int %}
    {% set TOOL = params.GATE|default(-1)|int %}
    {% set GATES = params.GATE|default('!')|string %}
    {% set TOOLS = params.GATE|default('!')|string %}
    MMU_CHECK_GATE GATE={GATE} TOOL={TOOL} GATES={GATES} TOOLS={TOOLS}

# Aliases (for backward compatibility)...

[gcode_macro MMU_CHANGE_TOOL_STANDALONE]
description: Convenience macro for inclusion in print_start for initial tool load
gcode:
    MMU_CHANGE_TOOL {rawparams} STANDALONE=1

[gcode_macro MMU_CHECK_GATES]
description: Alias for updated macro name of MMU_CHECK_GATE
gcode:
    MMU_CHECK_GATE {rawparams}


########################################################################
# Standalone Tip Forming (also helps with rapid tuning of Slicer values)
########################################################################
[gcode_macro _MMU_FORM_TIP_STANDALONE]
description: Standalone macro that mimics SuperSlicer process

# Unloading and Ramming values - Initial moves to form and shape tip
variable_unloading_speed_start: 80     # Fast here to seperate the filament from meltzone (Very intitial retract SS uses distance of E-15)
variable_unloading_speed: 18           # Too fast forms excessively long tip or hair. Slow is better here UNLOADING_SPEED_START/COOLING_MOVES seems a good start
variable_ramming_volume: 0             # (mm^3) SS default values = 2, 5, 9, 13, 18, 23, 27. Only Used to Simulate SS Ramming during standalone
variable_ss_ramming: 0                 # Set to 0 for standalone ramming (RAMMING_VOLUME), 1 to let the slicer do it (i.e. turn off for standalone)

# Cooling Move Values - To cool the tip formed and separate from strings
variable_cooling_tube_position: 35     # Dragon ST: 35, Dragon HF: 30, Mosquito: 30, Revo: 35, Phaetus Rapido HF: 43; Measured from nozzle to top of heater block
variable_cooling_tube_length: 10       # Dragon ST: 15, Dragon HF: 10, Mosquito: 20, Revo: 10, Phaetus Rapido HF: 22; Top of Heater block to top of heatsink
variable_initial_cooling_speed: 10     # Slow to solidify tip and cool string if formed.
variable_final_cooling_speed: 50       # High speed break the string formed. Too fast = tip deformation during eject. Too Slow = long string/no seperation
variable_toolchange_temp: 0            # Used if you want to lower temp during toolchanges default 0
variable_cooling_moves: 4              # 2-4 is a good start

# SkinnyDip values - To burn off VERY FINE hairs only (This is NOT for long tip reshaping)
variable_use_skinnydip: 1              # Tune this LAST, this is for removal of VERY FINE hairs only (Different than a long tip)
variable_skinnydip_distance: 30        # Start just under Cooling_tube_position and increase - Will depend on how much Ramming Volume is used
variable_dip_insertion_speed: 30       # Medium-Slow - Just long enough to melt the fine hairs. Too slow will pull up molten filament
variable_dip_extraction_speed: 70      # Around 2x Insertion speed, Prevents forming new hairs
variable_melt_zone_pause: 0            # Milliseconds - default 0
variable_cooling_zone_pause: 0         # Milliseconds - default 0 - If you need to adjust here its possible Dip Insertion too slow
variable_use_fast_skinnydip: 0         # Skip the toolhead temp change during skinnydip move - default 0


# Final Eject - for standalone tuning only. Automatically set by `MMU_FORM_TIP` command
variable_final_eject: 0                # Default 0, enable only when tuning process to eject the filament. Don't leave enabled!

# Park filament ready to eject
variable_parking_distance: 0           # Final filament parking position after final cooling move, 0 will leave filament where it naturally ends up

# Extruder speed for non specific movement
variable_extruder_move_speed: 1500       # Used for parking_distance and final_eject

gcode:
    # Initialize Paramaters
    {% set UNLOADING_SPEED_START = params.UNLOADING_SPEED_START|default(printer['gcode_macro _MMU_FORM_TIP_STANDALONE']['unloading_speed_start']) %}
    {% set UNLOADING_SPEED = params.UNLOADING_SPEED|default(printer['gcode_macro _MMU_FORM_TIP_STANDALONE']['unloading_speed']) %}
    {% set RAMMING_VOLUME = params.RAMMING_VOLUME|default(printer['gcode_macro _MMU_FORM_TIP_STANDALONE']['ramming_volume']) %}
    {% set SS_RAMMING = params.SS_RAMMING|default(printer['gcode_macro _MMU_FORM_TIP_STANDALONE']['ss_ramming']) %}
    {% set COOLING_TUBE_LENGTH = params.COOLING_TUBE_LENGTH|default(printer['gcode_macro _MMU_FORM_TIP_STANDALONE']['cooling_tube_length']) %}
    {% set COOLING_TUBE_POSITION = params.COOLING_TUBE_POSITION|default(printer['gcode_macro _MMU_FORM_TIP_STANDALONE']['cooling_tube_position']) %}
    {% set INITIAL_COOLING_SPEED = params.INITIAL_COOLING_SPEED|default(printer['gcode_macro _MMU_FORM_TIP_STANDALONE']['initial_cooling_speed']) %}
    {% set FINAL_COOLING_SPEED = params.FINAL_COOLING_SPEED|default(printer['gcode_macro _MMU_FORM_TIP_STANDALONE']['final_cooling_speed']) %}
    {% set COOLING_MOVES = params.COOLING_MOVES|default(printer['gcode_macro _MMU_FORM_TIP_STANDALONE']['cooling_moves']) %}
    {% set TOOLCHANGE_TEMP = params.TOOLCHANGE_TEMP|default(printer['gcode_macro _MMU_FORM_TIP_STANDALONE']['toolchange_temp']) %}
    {% set USE_SKINNYDIP = params.USE_SKINNYDIP|default(printer['gcode_macro _MMU_FORM_TIP_STANDALONE']['use_skinnydip']) %}
    {% set USE_FAST_SKINNYDIP = params.USE_FAST_SKINNYDIP|default(printer['gcode_macro _MMU_FORM_TIP_STANDALONE']['use_fast_skinnydip']) %}
    {% set SKINNYDIP_DISTANCE = params.SKINNYDIP_DISTANCE|default(printer['gcode_macro _MMU_FORM_TIP_STANDALONE']['skinnydip_distance']) %}
    {% set DIP_INSERTION_SPEED = params.DIP_INSERTION_SPEED|default(printer['gcode_macro _MMU_FORM_TIP_STANDALONE']['dip_insertion_speed']) %}
    {% set DIP_EXTRACTION_SPEED = params.DIP_EXTRACTION_SPEED|default(printer['gcode_macro _MMU_FORM_TIP_STANDALONE']['dip_extraction_speed']) %}
    {% set MELT_ZONE_PAUSE = params.MELT_ZONE_PAUSE|default(printer['gcode_macro _MMU_FORM_TIP_STANDALONE']['melt_zone_pause']) %}
    {% set COOLING_ZONE_PAUSE = params.COOLING_ZONE_PAUSE|default(printer['gcode_macro _MMU_FORM_TIP_STANDALONE']['cooling_zone_pause']) %}
    {% set EXTRUDER_MOVE_SPEED = params.EXTRUDER_MOVE_SPEED|default(printer['gcode_macro _MMU_FORM_TIP_STANDALONE']['extruder_move_speed']) %}
    {% set PARKING_DISTANCE = params.PARKING_DISTANCE|default(printer['gcode_macro _MMU_FORM_TIP_STANDALONE']['parking_distance']) %}
    {% set FINAL_EJECT = params.FINAL_EJECT|default(printer['gcode_macro _MMU_FORM_TIP_STANDALONE']['final_eject']) %}

    G91
    M83
    G92 E0
    
    #---------------------------------#
    #-Tip forming Process begins here-#
    #---------------------------------#

    SET_PRESSURE_ADVANCE ADVANCE=0
    {% set OLD_TEMP = printer.extruder.target %}
    {% if SS_RAMMING|int == 0 and RAMMING_VOLUME|int > 0 %} # Standalone Ramming
        {% set RATIO = (RAMMING_VOLUME|float) /23.0 %}
        G1 E{0.5784 * RATIO|float} F299 #7
        G1 E{0.5834 * RATIO|float} F302 #3
        G1 E{0.5918 * RATIO|float} F306 #6
        G1 E{0.6169 * RATIO|float} F319 #6
        G1 E{0.3393 * RATIO|float} F350 #0
        G1 E{0.3363 * RATIO|float} F350 #0
        G1 E{0.7577 * RATIO|float} F392 #6
        G1 E{0.8382 * RATIO|float} F434 #3
        G1 E{0.7776 * RATIO|float} F469 #9
        G1 E{0.1293 * RATIO|float} F469 #9
        G1 E{0.9673 * RATIO|float} F501 #2
        G1 E{1.0176 * RATIO|float} F527 #2
        G1 E{0.5956 * RATIO|float} F544 #6
        G1 E{0.4555 * RATIO|float} F544 #6
        G1 E{1.0662 * RATIO|float} F552 #4
    {% endif %}

    # Set toolchange temperature just prior to filament being extracted from melt zone and wait for set point
    # (SKINNYDIP -- normal mode only)
    # Only used if changing between filament types eg. ABS-->PLA
    {% if TOOLCHANGE_TEMP|float > 0 and USE_FAST_SKINNYDIP|int == 0 %}
         M109 S{TOOLCHANGE_TEMP}
    {% endif %}

    # Unloading - This is where the tip spear shape comes from Faster=longer/pointer/higher stringing
    {% set TOTAL_RETRACTION_DISTANCE = COOLING_TUBE_POSITION|float + COOLING_TUBE_LENGTH|float / 2 - 15 %}
    G1 E-15 F{1.0 * UNLOADING_SPEED_START|float * 60} # Default value from SS - Cannot modify
    G1 E-{0.7 * TOTAL_RETRACTION_DISTANCE} F{1.0 * UNLOADING_SPEED|float * 60}
    G1 E-{0.2 * TOTAL_RETRACTION_DISTANCE} F{0.5 * UNLOADING_SPEED|float * 60}
    G1 E-{0.1 * TOTAL_RETRACTION_DISTANCE} F{0.3 * UNLOADING_SPEED|float * 60}

    {% if TOOLCHANGE_TEMP|float > 0 and USE_FAST_SKINNYDIP|int == 1 %}
        M104 S{TOOLCHANGE_TEMP}
    {% endif %}

    # Generate Cooling Moves - Solidifies tip shape and helps break strings if formed
    {% set SPEED_INC = (FINAL_COOLING_SPEED|float - INITIAL_COOLING_SPEED|float) / (2 * COOLING_MOVES|float - 1) %}
    {% for move in range(COOLING_MOVES|int) %}
        G1 E{COOLING_TUBE_LENGTH} F{(INITIAL_COOLING_SPEED|float + SPEED_INC*move*2) * 60}
        G1 E-{COOLING_TUBE_LENGTH} F{(INITIAL_COOLING_SPEED|float + SPEED_INC*(move*2+1)) * 60}
    {% endfor %}

    # Wait for extruder to reach toolchange temperature after cooling moves complete (SKINNYDIP--fast mode only)
    {% if TOOLCHANGE_TEMP|float > 0 and USE_FAST_SKINNYDIP|int == 1 %}
        M109 S{TOOLCHANGE_TEMP}
    {% endif %}

    # Skinny dip Move - burns off VERY FINE hairs (Good for PLA)
    {% if USE_SKINNYDIP|int == 1 %}
        G1 E{SKINNYDIP_DISTANCE} F{DIP_INSERTION_SPEED|float * 60}
        G4 P{MELT_ZONE_PAUSE}
        G1 E-{SKINNYDIP_DISTANCE} F{DIP_EXTRACTION_SPEED|float * 60}
        G4 P{COOLING_ZONE_PAUSE}
    {% endif %}

    {% if TOOLCHANGE_TEMP|float > 0 %}
        M104 S{OLD_TEMP}
    {% endif %}
    
    # Eject once all shaping is done - Standalone mode only
    {% if FINAL_EJECT|int == 1 %}
        G92 E0
        G1 E-80 F{EXTRUDER_MOVE_SPEED|float * 60}
    # Park filament at fixed location
    {% elif PARKING_DISTANCE|int > 0 %}
        G90
        M82
        G1 E-{PARKING_DISTANCE} F{EXTRUDER_MOVE_SPEED|float * 60}
    {% endif %}

    G92 E0
    G90
    M82


########################################################################
# Standalone Tip Cutting
#
# If you use Filametrix then a custom macro is available in `mmu/base/mmu_filametrix.cfg`
# This can be configured as an alternative to _MMU_FORM_TIP_STANDALONE by setting
#   'form_tip_macro: _MMU_CUT_TIP' in mmu_parameters.cfg
#
#
# The park position of the filament is relative to the nozzle and represents where the end of the filament is
# after tip forming. The park position is important and used by Happy Hare to finish unloading the extruder
# and for how far to advance the filament on the subsequent load. If the filament is cut it is important
# to report back the position your cutter leaves the filament in the extruder relative to the nozzle.
#
# The value can be set dynamically in gcode with this construct:
#   SET_GCODE_VARIABLE MACRO=_MMU_CUT_TIP VARIABLE=output_park_pos VALUE=-1
# or preset as a variable like this:
#   variable_output_park_pos: 35
#
########################################################################


###########################################################################
# Callback macros for modifying Happy Hare behavior
# This occurs prior to unloading filament on a toolchange
#
# Typically you would move toolhead to a position where oozing is not a problem
# when using standalone tip forming.
# Note that the z_hop is automatically controlled by Happy Hare and is
# specified with the 'z_hop_height_toolchange' parameter
#
[gcode_macro _MMU_PRE_UNLOAD]
description: Optional pre unload routine for filament change
gcode:


###########################################################################
# Callback macros for modifying Happy Hare behavior
# This occurs immediately after the tip forming or cutting procedure
#
# This is a good place to move to a position where oozing is not a problem
# in the case of Tip Cutting where moving in the _MMU_PRE_UNLOAD is too early
#
[gcode_macro _MMU_POST_FORM_TIP]
description: Optional post tip forming/cutting routing
gcode:


###########################################################################
# Callback macros for modifying Happy Hare behavior
# This occurs immediately after unloading filament on a toolchange
#
# This is a good place to inject logic to, for example, perform
# tip cutting at the MMU preping the unloaded filment for the next time
# it is loaded
#
[gcode_macro _MMU_POST_UNLOAD]
description: Optional post unload routine for filament change
gcode:


###########################################################################
# Callback macros for modifying Happy Hare behavior
# This occurs after loading new filament on a toolchange
#
# Typically you would clean nozzle if equiped and return to previous position
# Note that restoration to original toolhead position is ensured by Happy Hare.
#
[gcode_macro _MMU_POST_LOAD]
description: Optional post load routine for filament change
gcode:


###########################################################################
# Callback macros for modifying Happy Hare behavior
# Note that EndlessSpool is an unsupervised filament change
# This occurs prior to MMU forming tip and ejecting the remains of the old filament
#
# Typically you would move toolhead to your park position so oozing is not a problem
# Note that the z_hop is automatically controlled by Happy Hare and is
# specified with the 'z_hop_height_toolchange' parameter
#
# This is probably similar to what you do in your PAUSE macro and you could simply call that here...
# (this call works with reference PAUSE macro supplied in client_macros.cfg)
#
[gcode_macro _MMU_ENDLESS_SPOOL_PRE_UNLOAD]
description: Optional post unload routine for EndlessSpool changes
gcode:
    PAUSE

###########################################################################
# Callback macros for modifying Happy Hare behavior
# Note that EndlessSpool is an unsupervised filament change
# This occurs after MMU has loaded the new filament from the next spool in rotation
# MMU will have loaded the new filament to the nozzle the same way as a normal filament
# swap. Previously configured Pressure Advance will be retained.
# 
# This would be a place to purge additional filament if necessary (it really shouldn't be)
# and clean nozzle if your printer is suitably equipped.
# Note that restoration to original toolhead position is ensured by Happy Hare.
#
# This is probably similar to what you do in your RESUME macro and you could simply call that here...
# (this call works with reference RESUME macro supplied in client_macros.cfg)
#
[gcode_macro _MMU_ENDLESS_SPOOL_POST_LOAD]
description: Optional post load routine for EndlessSpool changes
gcode:
    RESUME


###########################################################################
# This occurs when the MMU action status changes. The `ACTION` parameter will contain
# the current action string (also available in `printer.mmu.action` printer variable).
# Also the previous action is available in `OLD_ACTION`. See Happy Hare README for
# full list of action strings.
#
# Quick Action Ref:
#  Idle|Loading|Unloading|Loading Ext|Exiting Ext|Forming Tip|Heating|Checking|Homing|Selecting
#
# The reference logic here drives a set of optional LED's
#
[gcode_macro _MMU_ACTION_CHANGED]
description: Called when an action has changed
gcode:
    {% set ACTION = params.ACTION|string %}
    {% set OLD_ACTION = params.OLD_ACTION|string %}
    {% set gate = printer['mmu']['gate'] %}

    {% if ACTION == "Loading" %}
        _MMU_SET_LED EFFECT=mmu_pulsing_white_slow GATE={gate} EXIT_EFFECT=mmu_pulsing_white_slow
    {% elif ACTION == "Unloading" %}
        _MMU_SET_LED EFFECT=mmu_pulsing_white_slow GATE={gate} EXIT_EFFECT=mmu_pulsing_white_slow
    {% elif ACTION == "Heating" %}
        _MMU_SET_LED EFFECT=mmu_breathing_red GATE={gate} EXIT_EFFECT=mmu_breathing_red
    {% elif ACTION == "Idle" %}
        _MMU_SET_LED EFFECT=default EXIT_EFFECT=default
    {% elif ACTION == "Homing" or ACTION == "Selecting" %}
        {% if OLD_ACTION != "Homing" and OLD_ACTION != "Checking" %}
            _MMU_SET_LED EFFECT=mmu_pulsing_white_fast EXIT_EFFECT=off FADETIME=0
        {% endif %}
    {% elif ACTION == "Checking" %}
        _MMU_SET_LED EFFECT=default EXIT_EFFECT=mmu_pulsing_white_fast
    {% endif %}


###########################################################################
# This occurs when the MMU print state changes. The `STATE` parameter will contain
# the current state string (also available in `printer.mmu.print_state` printer variable)
# Also the previous action is available in `OLD_STATE`. See Happy Hare README for
# full list of state strings and the state transition diagram.
#
# Quick State Ref:
#  initialized|ready|started|printing|complete|cancelled|error|pause_locked|paused|standby
#
# The reference logic here drives a set of optional LED's
#
[gcode_macro _MMU_PRINT_STATE_CHANGED]
description: Called when print state changes
gcode:
    {% set STATE = params.STATE|string %}
    {% set OLD_STATE = params.OLD_STATE|string %}
    {% set gate = printer['mmu']['gate'] %}

    {% if STATE == "initialized" %}
        _MMU_SET_LED EFFECT=mmu_curtain DURATION=3
    {% elif STATE == "printing" %}
        _MMU_SET_LED EFFECT=default
    {% elif STATE == "pause_locked" %}
        _MMU_SET_LED EFFECT=mmu_strobe
    {% elif STATE == "paused" %}
        _MMU_SET_LED EFFECT=mmu_strobe GATE={gate} EXIT_EFFECT=mmu_strobe
    {% elif STATE == "ready" %}
        _MMU_SET_LED EFFECT=default EXIT_EFFECT=default
    {% elif STATE == "complete" %}
        _MMU_SET_LED EFFECT=mmu_sparkle DURATION=20 EXIT_EFFECT=default
    {% elif STATE == "error" %}
        _MMU_SET_LED EFFECT=mmu_strobe DURATION=20 EXIT_EFFECT=default
    {% elif STATE == "cancelled" %}
        _MMU_SET_LED EFFECT=default EXIT_EFFECT=default
    {% elif STATE == "standby" %}
        _MMU_SET_LED EFFECT=off EXIT_EFFECT=off
    {% endif %}


###########################################################################
# This occurs when the MMU gate_map (containing information about the filament
# type, color, availability and spoolId) is updated. The `GATE` parameter
# will contain the gate that is updated or -1 if all updated
#
# The reference logic here drives a set of optional LED's
#
[gcode_macro _MMU_GATE_MAP_CHANGED]
description: Called when gate map is updated
gcode:
    {% set GATE = params.GATE|int %}
    {% set effect = "" %}
    {% set exit_effect = "" %}
    {% set current_gate_effect = printer['gcode_macro _MMU_SET_LED']['current_gate_effect'] %}
    {% if current_gate_effect == "gate_status" or current_gate_effect == "filament_color" %}
        {% set effect=current_gate_effect %}
    {% endif %}
    {% set current_exit_effect = printer['gcode_macro _MMU_SET_LED']['current_exit_effect'] %}
    {% if current_gate_effect == "filament_color" %}
        {% set exit_effect=current_exit_effect %}
    {% endif %}
    {% if effect != "" or exit_effect != "" %}
        _MMU_SET_LED EFFECT={effect} EXIT_EFFECT={exit_effect}
    {% endif %}


###########################################################################
# Control macro for MMU neopixel or dotstar leds
#
[gcode_macro _MMU_SET_LED]
description: Called when print state changes

# Control the operation of MMU LED's. 0=Disabled (if you don't have neopixels for each gate)
variable_led_enable: 0

# Name of the neopixel or dotstar strip. Use complete name line in quotes e.g. "neopixel:mmu_leds"
variable_leds: "neopixel:mmu_leds"

# Default effect for gate LEDs.  This can be any effect or "r,g,b" color,
# but these are built-in functional effects:
# "off"             - LED's off when on action occuring
# "gate_status"     - indicate gate availability
# "filament_color"  - indicate filament color
variable_default_gate_effect: "gate_status"

# Default effect for exit LED, perhaps lighting the PTFE tube. This can be
# any effect or "r,g,b" color, but these are built-in functional effects:
# "off"             - LED's off except when on action occuring
# "on"              - LED's white (could be any effect or "r,g,b" color)
# "filament_color"  - indicate current filament color or white if not set
variable_default_exit_effect: "filament_color"

# Reverse chain order. If disabled (default), Gate 0 is LED index 1
# If enabled, Gate N is LED index 1
variable_reverse_gate_order: 0

# Advanced: If you are not using the first section of an LED chain this
# allows you to define the starting LED index. Note that it must match
# the start of the defined led_effect segments in 'mmu_hardware.cfg'
variable_first_led_index: 1

variable_current_gate_effect: "none"		# Internal state, don't mess
variable_current_exit_effect: "none"		# Internal state, don't mess

gcode:
    {% if printer['gcode_macro _MMU_SET_LED']['led_enable'] > 0 %}
        {% set leds = printer['gcode_macro _MMU_SET_LED']['leds'] %}
        {% set leds_name = leds.split(':')[1] %}
        {% set EFFECT = params.EFFECT|default("")|string %}
        {% set GATE = params.GATE|default(-1)|int %}
        {% set EXIT_EFFECT = params.EXIT_EFFECT|default("")|string %}
        {% set DURATION = params.DURATION|default(-1)|int %}
        {% set FADETIME = params.FADETIME|default(1)|int %}

        # Grab useful printer variables
        {% set gate_status = printer['mmu']['gate_status'] %}
        {% set gate_color = printer['mmu']['gate_color'] %}
        {% set gate_color_rgb = printer['mmu']['gate_color_rgb'] %}
        {% set filament_pos = printer['mmu']['filament_pos'] %}
        {% set white_light = (1,1,1) %}
        {% set black_light = (0.01,0,0.02) %}
        {% set empty_light = (0,0,0) %}

        # Determine LED indexes. Gates always first followed by "exit" LED
        {% set first_led_index = printer['gcode_macro _MMU_SET_LED']['first_led_index'] %}
        {% set exit_index = gate_status|length + first_led_index %}
        {% if printer['gcode_macro _MMU_SET_LED']['reverse_gate_order'] == 1 %}
            {% set index = gate_status|length - GATE + first_led_index %}
            {% set count = -1 %}
            {% set first = gate_status|length + first_led_index - 1 %}
        {% else %}
            {% set index = GATE + first_led_index %}
            {% set count = 1 %}
            {% set first = first_led_index %}
        {% endif %}

        {% if DURATION > 0 %}
            UPDATE_DELAYED_GCODE ID=_MMU_RESET_LED DURATION={DURATION}
        {% else %}
            UPDATE_DELAYED_GCODE ID=_MMU_RESET_LED DURATION=0
        {% endif %}

        {% if EFFECT == "default" %}
            {% set EFFECT = printer['gcode_macro _MMU_SET_LED']['default_gate_effect'] %}
        {% endif %}
        {% if EXIT_EFFECT == "default" %}
            {% set EXIT_EFFECT = printer['gcode_macro _MMU_SET_LED']['default_exit_effect'] %}
        {% endif %}

        SET_GCODE_VARIABLE MACRO=_MMU_SET_LED VARIABLE=current_gate_effect VALUE='"{EFFECT}"'
        SET_GCODE_VARIABLE MACRO=_MMU_SET_LED VARIABLE=current_exit_effect VALUE='"{EXIT_EFFECT}"'

        # Gate effects...
        {% if EFFECT == "off" %}
            {% if GATE >= 0 %}
                STOP_LED_EFFECTS LEDS="{leds} ({index})" FADETIME={FADETIME}
                SET_LED LED={leds_name} INDEX={index} RED=0 GREEN=0 BLUE=0 TRANSMIT=1
            {% else %}
                STOP_LED_EFFECTS LEDS={leds} FADETIME={FADETIME}
                SET_LED LED={leds_name} RED=0 GREEN=0 BLUE=0 TRANSMIT=1
            {% endif %}

        {% elif EFFECT == "gate_status" %} # Filament availability
            {% if GATE >= 0 %}
                {% if gate_status[GATE] == -1 %}
                    SET_LED_EFFECT EFFECT=mmu_orange_{index} FADETIME={FADETIME} REPLACE=1
                {% elif gate_status[GATE] > 0 %}
                    SET_LED_EFFECT EFFECT=mmu_green_{index} FADETIME={FADETIME} REPLACE=1
                {% else %}
                    STOP_LED_EFFECTS LEDS="{leds} ({index})" FADETIME={FADETIME}
                {% endif %}
            {% else %}
                {% set ns = namespace(index = first) %}
                {% for status in gate_status %}
                    {% if status == -1 %}
                        SET_LED_EFFECT EFFECT=mmu_orange_{ns.index} FADETIME={FADETIME} REPLACE=1
                    {% elif status > 0 %}
                        SET_LED_EFFECT EFFECT=mmu_green_{ns.index} FADETIME={FADETIME} REPLACE=1
                    {% else %}
                        STOP_LED_EFFECTS LEDS="{leds} ({ns.index})" FADETIME={FADETIME}
                        SET_LED LED={leds_name} INDEX={ns.index} RED=0 GREEN=0 BLUE=0 TRANSMIT=1
                    {% endif %}
                    {% set ns.index = ns.index + count %}
                {% endfor %}
            {% endif %}

        {% elif EFFECT == "filament_color" %} # Filament color
            {% if GATE >= 0 %}
                {% set rgb = gate_color_rgb[GATE] %}
                STOP_LED_EFFECTS LEDS="{leds} ({index})"
                SET_LED LED={leds_name} INDEX={index} RED={rgb[0]} GREEN={rgb[1]} BLUE={rgb[2]} TRANSMIT=1
            {% else %}
                STOP_LED_EFFECTS LEDS={leds}
                {% set ns = namespace(index = first, gate = 0) %}
                {% for rgb in gate_color_rgb %}
                    {% if gate_status[ns.gate] != 0 %}
                        {% if gate_color[ns.gate] == "" %}
                            {% set rgb = white_light %}
                        {% elif rgb == (0,0,0) %}
                            {% set rgb = black_light %}
                        {% endif %}
                    {% else %}
                        {% set rgb = empty_light %}
                    {% endif %}
                    SET_LED LED={leds_name} INDEX={ns.index} RED={rgb[0]} GREEN={rgb[1]} BLUE={rgb[2]} TRANSMIT=1
                    {% set ns.index = ns.index + count %}
                    {% set ns.gate = ns.gate + 1 %}
                {% endfor %}
            {% endif %}

        {% elif "," in EFFECT %} # Not effect, just simple RGB color
            {% set rgb = EFFECT.split(",") %}
            {% if GATE >= 0 %}
                STOP_LED_EFFECTS LEDS="{leds} ({index})"
                SET_LED LED={leds_name} INDEX={index} RED={rgb[0]} GREEN={rgb[1]} BLUE={rgb[2]} TRANSMIT=1
            {% else %}
                STOP_LED_EFFECTS LEDS={leds}
                SET_LED LED={leds_name} RED={rgb[0]} GREEN={rgb[1]} BLUE={rgb[2]} TRANSMIT=1
            {% endif %}

        {% elif EFFECT != "" %} # Simple effect by name
            {% if GATE >= 0 %}
                SET_LED_EFFECT EFFECT={EFFECT}_{index} FADETIME={FADETIME} REPLACE=1
            {% else %}
                SET_LED_EFFECT EFFECT={EFFECT} FADETIME={FADETIME} REPLACE=1
            {% endif %}
        {% endif %}

        # Exit effects...
        {% if EXIT_EFFECT == "off" %}
            STOP_LED_EFFECTS LEDS="{leds} ({exit_index})" FADETIME={FADETIME}
            SET_LED LED={leds_name} INDEX={exit_index} RED=0 GREEN=0 BLUE=0 TRANSMIT=1

        {% elif EXIT_EFFECT == "filament_color" or EXIT_EFFECT == "on" %} # Filament color
            {% set gate = printer['mmu']['gate'] %}
            STOP_LED_EFFECTS LEDS="{leds} ({exit_index})"
            {% if gate >= 0 and filament_pos > 0 %}
                {% if EXIT_EFFECT != "on" and gate_color[gate] != "" %}
                    {% set rgb = gate_color_rgb[gate] %}
                {% else %}
                    {% set rgb = white_light %}
                {% endif %}
                SET_LED LED={leds_name} INDEX={exit_index} RED={rgb[0]} GREEN={rgb[1]} BLUE={rgb[2]} TRANSMIT=1
            {% else %}
                SET_LED LED={leds_name} INDEX={exit_index} RED=0 GREEN=0 BLUE=0 TRANSMIT=1
            {% endif %}

        {% elif "," in EXIT_EFFECT %} # No effect, just simple RGB color
            {% set rgb = EXIT_EFFECT.split(",") %}
            STOP_LED_EFFECTS LEDS="{leds} ({exit_index})"
            SET_LED LED={leds_name} INDEX={exit_index} RED={rgb[0]} GREEN={rgb[1]} BLUE={rgb[2]} TRANSMIT=1

        {% elif EXIT_EFFECT != "" %} # Simple effect by name
            SET_LED_EFFECT EFFECT={EXIT_EFFECT}_{exit_index} FADETIME={FADETIME} REPLACE=1
        {% endif %}
    {% endif %}


###########################################################################
# Helper for LED control
#
[delayed_gcode _MMU_RESET_LED]
gcode:
    _MMU_SET_LED EFFECT=default EXIT_EFFECT=default

